#include "ParseMP4.h"


int parse_mp4(char* filePath,struct Meta* ret_m)
{
	FILE *fp;
	

	unsigned char Atom_size[4];
	unsigned char Atom_type[4];

	unsigned char Atom_size64[8];

	unsigned char EntryN[4];
	int EntryNumber=0;

	unsigned char MINOR_Header[4];
	unsigned char MINOR_Size[4];

	unsigned char CODEC_Buffer[100];

	unsigned char CODEC_BRAND[4];

	char* AtomTypeChar;

	unsigned char hdlr_flag[10];
	unsigned char hdlr_type[10];

	unsigned char CODEC_ID[20];

	unsigned char timeScale[4];
	unsigned char duration[4];

	unsigned char width[2];
	unsigned char height[2];


	unsigned char tmp_Header[4];
	unsigned char tmp_Size[4];

	unsigned char FProfile[2];
	unsigned char FProfile_version[1];



	char test[]="test";
	char VersionStr[100];

	float Version=0.0;


	int offset = 0;

	int width_ =0;
	int height_ = 0;

	int FULFILLED_CNT = 0;
	int i = 0;
	size_t count;


	long destination = 0;

	long size=0;
	long size64 = 0;

	long MileStone=0;
	long tmpIdx=0;


	int lcnt=0;


	fp = fopen(filePath,"rb");

	
	if(fp == NULL){
		return 0;
	}


	ret_m->fileSize = GetFileLength(fp);

	ret_m->upnpClass=(char*)malloc(strlen(UPNP_VIDEO)+1);
	strcpy(ret_m->upnpClass,UPNP_VIDEO);

	ret_m->ProtocolInfo = (char*)malloc(strlen(PROTOCOL_MP4)+1);
	strcpy(ret_m->ProtocolInfo,PROTOCOL_MP4);



//	printf("\n");

//	while( i++ < 50 && ftell(fp) < ret_m->fileSize ){
	fread(Atom_size, sizeof(char), (size_t)4,fp);
	fread(Atom_type, sizeof(char), (size_t)4,fp);
	
	while(FULFILLED_CNT < 5&& ftell(fp) < ret_m->fileSize){





		size = getIntFrom4Byte(Atom_size);
		destination = ftell(fp)+size;
//		printf("%c%c%c%c, Offset-> %x (jump to %x ), %x\n",Atom_type[0],Atom_type[1],Atom_type[2],Atom_type[3],ftell(fp),size, ftell(fp)+size);
		if(size == 1 )
		{
			fread(Atom_size64,sizeof(char),(size_t)8,fp);
			size64 = getIntFromByte(Atom_size64,8);
			size = size64 - 8;
		}



		offset += size;

		if(size == 0)
		{
			

		}
	
	
		if( strncmp(Atom_type,"ftyp",4) == 0 )
		{
			fread(CODEC_BRAND,sizeof(char),(size_t)4,fp);
			
			ret_m->CodecBrand = (char*)malloc(5);

			getStringFromBuffer(CODEC_BRAND,ret_m->CodecBrand,4);

			fseek(fp,offset , SEEK_SET);

		}
		else if( strncmp(Atom_type,"hdlr",4) == 0)
		{

			if( strncmp(hdlr_flag, "mdia",4) == 0 )
			{
				fseek(fp,8,SEEK_CUR);
				fread(hdlr_type, sizeof(char),(size_t)4,fp);
				fseek(fp, size- 20, SEEK_CUR);
			}else
			{
				fseek(fp, size- 8 , SEEK_CUR);
			}


		}
		
		else if( strncmp(Atom_type, "stsd",4 ) == 0 )
		{
			fseek(fp,4,SEEK_CUR);
			fread(EntryN,sizeof(char),(size_t)4,fp);

			EntryNumber = getIntFrom4Byte(EntryN);
				
			for(i = 0 ; i < EntryNumber ; i++)
			{
				fread(MINOR_Size,sizeof(unsigned char),(size_t)4,fp);
				fread(MINOR_Header,sizeof(unsigned char),(size_t)4,fp);

				getStringFromBuffer(MINOR_Header,CODEC_Buffer,4);
				
				if(strncmp(CODEC_ID,"vmhd",4) == 0)
				{
					MileStone = ftell(fp) + getIntFrom4Byte(MINOR_Size)-8;
					if(strcmp(CODEC_Buffer,"avc1") == 0 )
					{
						//Let's FindOut the Profile
		//				printf("\nAVC1s FOUND\n");
						fseek(fp,0x4e,SEEK_CUR);
						
						while(tmpIdx < MileStone){
							fread(tmp_Size,sizeof(unsigned char),4,fp);
							fread(tmp_Header,sizeof(unsigned char),4,fp);

	//						printf("\n%c%c%c%c\n",tmp_Header[0],tmp_Header[1],tmp_Header[2],tmp_Header[3]);
							if(strncmp(tmp_Header,"avcC",4) == 0)
							{
							
								fseek(fp,1,SEEK_CUR);
								fread(FProfile,sizeof(unsigned char),2,fp);
								fread(FProfile_version,sizeof(unsigned char),1,fp);

//								printf("\nPROFILE1 %x %d\n",FProfile[0],FProfile[0]);
//								printf("\nPROFILE %x %d \n",FProfile[1],FProfile[1]);
//								printf("\nVERSION %x %d\n",FProfile_version[0],FProfile_version[0]);

								Version = (float)FProfile_version[0] / 10.0;

								if(FProfile[0] == 0x4d)
								{
	//								printf("MAIN!");
									sprintf(VersionStr," Main@%.1f",Version);
									strcat(CODEC_Buffer,VersionStr);					
									//MainProfile
								}
								else if(FProfile[0] == 0x64) 
								{
	//								printf("HIGH!");
									sprintf(VersionStr," High@%.1f",Version);
									strcat(CODEC_Buffer,VersionStr);
									//HighProfile
								}else if(FProfile[0] == 0x42)
								{
	//								printf("BASE!");
									sprintf(VersionStr," Base@%.1f",Version);
									strcat(CODEC_Buffer,VersionStr);
									//Baseline
								}
	//							printf("  => %s\n",VersionStr);

							}
							else
								fseek(fp,getIntFrom4Byte(tmp_Size)-8,SEEK_CUR);


							tmpIdx = ftell(fp);
						}
						
						fseek(fp,MileStone-getIntFrom4Byte(MINOR_Size)+8,SEEK_SET);

					}
		
					ret_m->VID_CODEC = (char*)malloc(strlen(CODEC_Buffer)+1);
					strcpy(ret_m->VID_CODEC,CODEC_Buffer);
					FULFILLED_CNT++;
					
				}
				else if(strncmp(CODEC_ID,"smhd",4) == 0)
				{
					ret_m->AUD_CODEC = (char*)malloc(strlen(CODEC_Buffer)+1);
					strcpy(ret_m->AUD_CODEC,CODEC_Buffer);
					FULFILLED_CNT++;
					
				}
				
				
				fseek(fp,getIntFrom4Byte(MINOR_Size)-8,SEEK_CUR);
				
			}



		}
		else if( strncmp(Atom_type, "minf",4 ) == 0)
		{
			strcpy(hdlr_flag,"minf");

			
		}
		else if( strncmp(Atom_type, "stbl",4) == 0)
		{

		}
	
		else if(strncmp(Atom_type, "mdia",4) == 0)
		{
			strcpy(hdlr_flag , "mdia");
	
		}
		else if(strncmp(Atom_type, "moov",4) == 0)
		{

		}
		else if(strncmp(Atom_type, "trak",4) == 0)
		{
		
		}
		else if(strncmp(Atom_type, "mvhd",4) == 0)
		{
	
			fseek(fp, 12, SEEK_CUR);
			fread(timeScale, sizeof(char), (size_t)4, fp);
			fread(duration, sizeof(char), (size_t)4, fp);
			fseek(fp, size-28, SEEK_CUR);

			ret_m->Duration = getIntFrom4Byte(duration) / getIntFrom4Byte(timeScale) ;

			FULFILLED_CNT++;

		}
		else if(strncmp(Atom_type, "tkhd",4) == 0)
		{
	
			fseek(fp, 76, SEEK_CUR);
			
			fread(width, sizeof(char), (size_t)2, fp);
			fseek(fp,2,SEEK_CUR);
			fread(height,sizeof(char),(size_t)2,fp);
	
			fseek(fp,2,SEEK_CUR);

			width_ = getIntFromByte(width,2);
			height_ = getIntFromByte(height,2);

		
			if(width_ > ret_m->ResolutionX ){

				if(width_ > 100)
					FULFILLED_CNT++;
				ret_m->ResolutionX = width_;

			}
			if(height_ > ret_m->ResolutionY){
				if(height_ > 100)
					FULFILLED_CNT++;

				ret_m->ResolutionY = height_;
		
			}


		}
		else if(strncmp(Atom_type,"mdhd",4) == 0)
		{
	
			fseek(fp,size-8,SEEK_CUR);
			


		}
		else if(strncmp(Atom_type,"vmhd",4)==0)
		{
			strcpy(CODEC_ID,"vmhd");
			fseek(fp,size-8,SEEK_CUR);

		}
		else if( strncmp(Atom_type,"smhd",4) == 0)
		{
			strcpy(CODEC_ID,"smhd");
			fseek(fp,size-8,SEEK_CUR);
		}
		else{

			offset = ftell(fp);
			fseek(fp,offset+size-8,SEEK_SET);

			
		}

		fread(Atom_size, sizeof(unsigned char), (size_t)4,fp);
		fread(Atom_type, sizeof(unsigned char), (size_t)4,fp);


	}





	

	printf("\n-Mp4(mov) Parsing Results.------\n");
	printf("Format	  : %s\n",ret_m->Container);
	printf("File Size : %d\n",ret_m->fileSize);
	printf("Duration  : %d\n",ret_m->Duration);
	printf("Resolution: %dx%d\n",ret_m->ResolutionX,ret_m->ResolutionY);
	printf("Brand	  : %s\n",ret_m->CodecBrand);
	printf("V-CODEC   : %s\n",ret_m->VID_CODEC);
	printf("A-CODEC	  : %s\n",ret_m->AUD_CODEC); 
	printf("Protocol  : %s\n",ret_m->ProtocolInfo);
	printf("UpnpClass : %s\n",ret_m->upnpClass);
	printf("-------------------------");



	fclose(fp);
	return FILE_MOVIE;


}

int getAudCodecFromCode(int code, char* CODEC){

	switch(code)
	{
	case 0x0055:
		strcpy(CODEC,"MP3");
		break;
	case 0x2000:
		strcpy(CODEC,"AC3");
		break;
	case 0x2001:
		strcpy(CODEC,"DTS");
		break;

	default:

		strcpy(CODEC,"UNKNOWN");

	}

	return 0;


}